from datetime import timedelta, datetime
from pytz import timezone
from typing import Dict, List, Optional
from copy import deepcopy

import pandas as pd
import jqdatasdk as jqdata

# from vnpy.trader.setting import SETTINGS
from vnpy.feeds.datafeed import BaseDatafeed
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.object import BarData, HistoryRequest, FutBasicData, FutBasicRequest, FutMappingData
from vnpy.trader.utility import round_to

# 数据频率映射
INTERVAL_VT2TS = {
    Interval.MINUTE: "minute",
    Interval.HOUR: "60m",
    Interval.DAILY: "daily",
}


# 单位时间长度, 几天或者几分钟, 现在支持'Xd','Xm', 'daily'(等同于'1d'), 'minute'(等同于'1m'), X是一个正整数, 分别表示X天和X分钟

# 股票支持列表
STOCK_LIST = [
    Exchange.SSE,
    Exchange.SZSE,
    Exchange.BSE,
]

# 期货支持列表
FUTURE_LIST = [
    Exchange.CFFEX,
    Exchange.SHFE,
    Exchange.CZCE,
    Exchange.DCE,
    Exchange.INE,
]

# 交易所映射
EXCHANGE_VT2TS = {
    Exchange.CFFEX: "CFX",
    Exchange.SHFE: "SHF",
    Exchange.CZCE: "ZCE",
    Exchange.DCE: "DCE",
    Exchange.INE: "INE",
    Exchange.SSE: "SH",
    Exchange.SZSE: "SZ",
}

# 时间调整映射
INTERVAL_ADJUSTMENT_MAP = {
    Interval.MINUTE: timedelta(minutes=1),
    Interval.HOUR: timedelta(hours=1),
    Interval.DAILY: timedelta()
}

# 中国上海时区
CHINA_TZ = timezone("Asia/Shanghai")


def to_ts_symbol(symbol, exchange) -> Optional[str]:
    """将交易所代码转换为tushare代码"""
    # 股票
    if exchange in STOCK_LIST:
        ts_symbol = f"{symbol}.{EXCHANGE_VT2TS[exchange]}"
    # 期货
    elif exchange in FUTURE_LIST:
        ts_symbol = f"{symbol}.{EXCHANGE_VT2TS[exchange]}".upper()
    else:
        return None

    return ts_symbol


def to_ts_asset(symbol, exchange) -> Optional[str]:
    """生成tushare资产类别"""
    # 股票
    if exchange in STOCK_LIST:
        if exchange is Exchange.SSE and symbol[0] == "6":
            asset = "E"
        elif exchange is Exchange.SZSE and symbol[0] == "0" or symbol[0] == "3":
            asset = "E"
        else:
            asset = "I"
    # 期货
    elif exchange in FUTURE_LIST:
        asset = "FT"
    else:
        return None

    return asset


class JQDataDatafeed(BaseDatafeed):
    """JQData数据服务接口"""

    def __init__(self, username="13296736675", password="Jqjiejin264"):
        """"""
        self.username: str = username
        self.username: str = password
        self.inited: bool = False

    def init(self) -> bool:
        """初始化"""
        if self.inited:
            return True

        # jqdata.auth(self.username, self.password)
        jqdata.auth("13296736675", "Jqjiejin264")
        self.inited = True

        return True

    def query_bar_history(self, req: HistoryRequest) -> Optional[List[BarData]]:
        """查询k线数据"""
        if not self.inited:
            self.init()

        security = jqdata.normalize_code(req.symbol)
        datetime_format = "%Y-%m-%d"
        symbol = req.symbol
        exchange = req.exchange
        interval = req.interval
        if req.interval == Interval.MINUTE:
            once_time = timedelta(days=1)
        else:
            once_time = timedelta(days=1000)

        temp_start = req.start
        temp_end = req.start + once_time

        data = pd.DataFrame()

        # ts_symbol = to_ts_symbol(symbol, exchange)
        # if not ts_symbol:
        #     return None

        # asset = to_ts_asset(symbol, exchange)
        # if not asset:
        #     return None

        ts_interval = INTERVAL_VT2TS.get(interval)
        if not ts_interval:
            return None

        start = req.start.strftime(datetime_format)
        end = temp_end.strftime(datetime_format)

        adjustment = INTERVAL_ADJUSTMENT_MAP[interval]
        fields = ['open', 'close', 'high', 'low', 'volume', 'open_interest']
        try:
            df = jqdata.get_price(security,
                                  start_date=temp_start.strftime(datetime_format),
                                  end_date=temp_end.strftime(datetime_format),
                                  frequency=ts_interval,
                                  fields=fields,
                                  fq='pre')
            data = pd.concat([data, df])
            temp_start = temp_end
            temp_end = temp_end + once_time
        except IOError:
            return data

        while True:
            if len(df) == 0:
                break
            # tmp_end = df.index[-1]
            df = jqdata.get_price(security,
                                  start_date=temp_start.strftime(datetime_format),
                                  end_date=temp_end.strftime(datetime_format),
                                  frequency=ts_interval,
                                  fields=fields,
                                  fq='pre')

            data = pd.concat([data, df])

        data.columns = ['Open', 'Close', 'High', 'Low', 'Volume', 'OpenInterest']
        data['Datetime'] = data.index
        data['Symbol'] = req.symbol
        data['Exchange'] = exchange
        data['Gateway'] = 'JQData'
        data['Interval'] = req.interval

        return data


    def get_all_securities(self):
        # jqdata.get_all_securities(types=[], date=None)
        types = ['stock', 'fund', 'index', 'futures', 'etf', 'lof']
        types = ['futures']
        df = jqdata.get_all_securities(types=types, date=None)
        df['Symbol'] = df.index
        # print(df)
        return df

    def query_fut_basic(self, req: FutBasicRequest) -> Optional[List[FutBasicData]]:

        """获取期货合约列表数据"""
        if not self.inited:
            self.init()

        exchange = req.exchange
        fut_type = req.fut_type

        exchanges = ["SHFE", "CZCE", "DCE", "CFFEX"]
        data: List[FutData] = []

        for exchange in exchanges:
            df: DataFrame = self.pro.query('fut_basic', **{
                "exchange": exchange,
                "fut_type": "",
                "ts_code": "",
                "limit": "",
                "offset": ""
            }, fields=[
                "ts_code",
                "symbol",
                "exchange",
                "name",
                "fut_code",
                "multiplier",
                "trade_unit",
                "per_unit",
                "quote_unit",
                "quote_unit_desc",
                "d_mode_desc",
                "list_date",
                "delist_date",
                "d_month",
                "last_ddate",
                "trade_time_desc"
            ])

            print(df.head(2).to_string())

            if len(df):
                for _, row in df.iterrows():
                    fut = FutBasicData(
                        gateway_name="tushare",
                        ts_code=row.ts_code,
                        symbol=row.symbol,
                        exchange=Exchange(row.exchange),
                        name=row['name'],
                        fut_code=row.fut_code,
                        multiplier=row.multiplier,
                        trade_unit=row.trade_unit,
                        per_unit=row.per_unit,
                        quote_unit=row.quote_unit,
                        quote_unit_desc=row.quote_unit_desc,
                        d_mode_desc=row.d_mode_desc,
                        list_date=row.list_date,
                        delist_date=row.delist_date,
                        d_month=row.d_month,
                        last_ddate=row.last_ddate,
                        trade_time_desc=row.trade_time_desc
                    )

                    data.append(fut)

        return data

        if not self.inited:
            self.init()

    def query_fut_mapping(self, ts_code: str, start_date: str, end_date: str) \
            -> Optional[List[FutMappingData]]:
        """获取期货合约列表数据"""
        if not self.inited:
            self.init()

        # exchange = req.exchange
        # fut_type = req.fut_type

        data: List[FutMappingData] = []

        df: DataFrame = self.pro.fut_mapping(**{
            "ts_code": "SAL.ZCE",
            "trade_date": "",
            "start_date": 20220701,
            "end_date": 20220708,
            "limit": "",
            "offset": ""
        }, fields=[
            "ts_code",
            "trade_date",
            "mapping_ts_code"
        ])

        print(df.head().to_string())

        if len(df):
            for _, row in df.iterrows():
                fut = FutMappingData(
                    gateway_name="tushare",
                    ts_code=row.ts_code,
                    trade_date=row.trade_date,
                    mapping_ts_code=row.mapping_ts_code
                )
                data.append(fut)

        return data
